home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 4
/
Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso
/
Development
/
General
/
DR1.#1 PowerPlant ƒ
/
LWindow.cp
< prev
next >
Wrap
Text File
|
1994-02-10
|
39KB
|
1,510 lines
// ===========================================================================
// LWindow.cp ©1993 Metrowerks Inc. All rights reserved.
// ===========================================================================
#include "LWindow.h"
#include "LModelProperty.h"
#include "LStream.h"
#include "PP_Messages.h"
#include "UAppleEvents.h"
#include "UExtractFromAEDesc.h"
#include "UDesktop.h"
#include "UReanimator.h"
#include "UWindows.h"
#include <AERegistry.h>
#include <AEObjects.h>
#include <AEPackObject.h>
const DescType pPosition = 'ppos';
// ---------------------------------------------------------------------------
// • LWindow
// ---------------------------------------------------------------------------
// Default Constructor
LWindow::LWindow()
{
mMacWindowP = nil;
mStandardSize.width = 32767;
mStandardSize.height = 32767;
mMoveOnlyUserZoom = false;
mAttributes = windAttr_Regular;
}
// ---------------------------------------------------------------------------
// • ~LWindow
// ---------------------------------------------------------------------------
// Destructor
LWindow::~LWindow()
{
if (mMacWindowP != nil) {
// Hide window to ensure proper
// ordering of remaining windows
UDesktop::HideDeskWindow(this);
// Delete subpanes *before* disposing of Toolbox WindowRecord.
// The LView destructor will delete subpanes, but it gets
// called after this destructor (since LWindow is derived
// from LView). If we dispose of the Toolbox WindowRecord first,
// it causes problems for Panes based on other Toolbox data
// structures, such as standard Controls and TextEdit, that
// store their own reference to a WindowRecord.
DeleteAllSubPanes();
DisposeWindow(mMacWindowP); // Kill Toolbox Window
mMacWindowP = nil;
}
}
LWindow*
LWindow::CreateWindow(
ResIDT inWindowID,
LCommander *inSuperCommander)
{
SetDefaultCommander(inSuperCommander);
LWindow *theWindow =
(LWindow*) UReanimator::ReadObjects('PObj', inWindowID);
theWindow->FinishCreate();
if (theWindow->HasAttribute(windAttr_ShowNew)) {
theWindow->Show();
}
return theWindow;
}
LWindow*
LWindow::CreateWindowStream(
LStream *inStream)
{
DataIDT dataID;
inStream->ReadData(&dataID, sizeof(DataIDT));
SignalIf_(dataID != 'Wind');
return (new LWindow(inStream));
}
LWindow::LWindow(
LStream *inStream)
{
ResIDT windResID;
inStream->ReadData(&windResID, sizeof(ResIDT));
inStream->ReadData(&mAttributes, sizeof(Uint16));
mStandardSize.width = 32767;
mStandardSize.height = 32767;
mMoveOnlyUserZoom = false;
MakeMacWindow(windResID);
EstablishPort();
OutOfFocus(nil);
SetDefaultView(this);
}
// ---------------------------------------------------------------------------
// • MakeMacWindow
// ---------------------------------------------------------------------------
// Make a new Mac Window from a WIND resource template
void
LWindow::MakeMacWindow(
Int16 inWINDid)
{
SetPaneID(inWINDid);
mMacWindowP = UDesktop::NewDeskWindow(this, inWINDid, window_InFront);
if (mMacWindowP == nil) {
Throw_(666); // ### Error, couldn't make window
}
// Inside Mac says that an Application may set the windowKind
// field of a WindowRecord to any value greater than 8 if
// desired. PowerPlant requires that the windowKind for
// windows associated with a LWindow object be >= PP_Window_Kind,
// which is a large constant. For such windows, we PowerPlant
// stores a pointer to the LWindow object in the refCon.
// If you wish to use unique kinds for your windows (it's the
// only way to differentiate LWindow subclasses from just looking
// at a Toolbox WindowRecord), store the kind number in the
// refCon field of the WIND resource.
// Get WIND resource to check refCon
SWINDResourceH theWIND = (SWINDResourceH) GetResource('WIND', inWINDid);
Int16 kind = (**theWIND).refCon;
if (kind < PP_Window_Kind) { // Use value from refCon if it is
kind = PP_Window_Kind; // greater than our special number
}
((WindowPeek) mMacWindowP)->windowKind = kind;
ReleaseResource((Handle) theWIND);
// Stuff object pointer in refcon
SetWRefCon(mMacWindowP, (long) this);
// Window Frame and Image are the same
// as its portRect
ResizeFrameTo(mMacWindowP->portRect.right - mMacWindowP->portRect.left,
mMacWindowP->portRect.bottom - mMacWindowP->portRect.top,
false);
ResizeImageTo(mMacWindowP->portRect.right - mMacWindowP->portRect.left,
mMacWindowP->portRect.bottom - mMacWindowP->portRect.top,
false);
mMinMaxSize.left = 100; // ### Hardwired
mMinMaxSize.top = 100;
// Default max Window size to the dimensions
// of the Gray Region, which is the total
// Desktop size across all screens
Rect grayBox = (**(GetGrayRgn())).rgnBBox;
mMinMaxSize.right = grayBox.right - grayBox.left;
mMinMaxSize.bottom = grayBox.bottom - grayBox.top;
CalcRevealedRect();
CalcPortFrameRect(mUserBounds);
PortToGlobalPoint(topLeft(mUserBounds));
PortToGlobalPoint(botRight(mUserBounds));
#if 0 // Code above does same thing without direct access to vars
if (HasAttribute(windAttr_Enabled)) {
Enable();
} else {
Disable();
}
Hide();
Deactivate();
#endif
mVisible = triState_Off;
mActive = triState_Off;
mEnabled = triState_Off;
if (HasAttribute(windAttr_Enabled)) {
mEnabled = triState_On;
}
}
// ---------------------------------------------------------------------------
// • FetchWindowObject
// ---------------------------------------------------------------------------
// Return the PowerPlant Window object associated with a Mac WindowPtr
//
// Returns nil if the WindowPtr is not a PowerPlant Window
LWindow*
LWindow::FetchWindowObject(
WindowPtr inWindowP)
{
LWindow *ppWindow = nil;
// PowerPlant Windows have a special
// windowKind
if ( (inWindowP != nil) &&
(((WindowPeek) inWindowP)->windowKind >= PP_Window_Kind) ) {
// Object pointer is in the refCon
ppWindow = (LWindow*) GetWRefCon(inWindowP);
}
return ppWindow;
}
GrafPtr
LWindow::GetMacPort() const
{
return mMacWindowP;
}
// ---------------------------------------------------------------------------
// • HasAttribute
// ---------------------------------------------------------------------------
// Return whether a Window has the specified attribute
Boolean
LWindow::HasAttribute(
EWindAttr inAttribute) const
{
return ((mAttributes & inAttribute) != 0);
}
void
LWindow::GetMinMaxSize(
Rect &outRect) const
{
outRect = mMinMaxSize;
}
void
LWindow::SetMinMaxSize(
const Rect &inRect)
{
mMinMaxSize = inRect;
}
void
LWindow::GetStandardSize(
SDimension16 &outStdSize)
{
outStdSize = mStandardSize;
}
void
LWindow::SetStandardSize(
SDimension16 inStdSize)
{
mStandardSize = inStdSize;
}
StringPtr
LWindow::GetDescriptor(
Str255 outDescriptor) const
{
GetWTitle(mMacWindowP, outDescriptor);
return outDescriptor;
}
void
LWindow::SetDescriptor(
ConstStr255Param inDescriptor)
{
SetWTitle(mMacWindowP, inDescriptor);
}
// ---------------------------------------------------------------------------
// • HandleClick
// ---------------------------------------------------------------------------
// Respond to a click on a Window
//
// The inPart parameter is the part code returned by the Toolbox FindWindow
// routine.
void
LWindow::HandleClick(
const EventRecord& inMacEvent,
Int16 inPart)
{
switch (inPart) {
case click_OutsideModal: // Special case for clicking outside
SysBeep(1); // a modal window
break;
case inContent:
ClickInContent(inMacEvent);
break;
case inDrag:
ClickInDrag(inMacEvent);
break;
case inGrow:
ClickInGrow(inMacEvent);
break;
case inGoAway:
ClickInGoAway(inMacEvent);
break;
case inZoomIn:
case inZoomOut:
ClickInZoom(inMacEvent, inPart);
break;
}
}
// ---------------------------------------------------------------------------
// • ClickInContent
// ---------------------------------------------------------------------------
// Respond to a click in the content region of a Window
void
LWindow::ClickInContent(
const EventRecord& inMacEvent)
{
// Enabled Windows respond to clicks
Boolean respondToClick = HasAttribute(windAttr_Enabled);
// Set up our extended event record
SMouseDownEvent theMouseDown;
theMouseDown.wherePort = inMacEvent.where;
GlobalToPortPoint(theMouseDown.wherePort);
theMouseDown.whereLocal = theMouseDown.wherePort;
theMouseDown.macEvent = inMacEvent;
theMouseDown.delaySelect = false;
if (!UDesktop::WindowIsSelected(this)) {
// Window is not in front, we might
// need to select it
Boolean doSelect = true;
if (HasAttribute(windAttr_DelaySelect)) {
// Delay selection until after handling
// the click (called click-through)
theMouseDown.delaySelect = true;
Click(theMouseDown);
// After click-through, we select the
// Window if the mouse is still down
// or the mouse up occurred inside
// this Window.
EventRecord mouseUpEvent;
if (!StillDown() && GetOSEvent(mUpMask, &mouseUpEvent)) {
// Check location of mouse up event
WindowPtr upWindow;
FindWindow(mouseUpEvent.where, &upWindow);
doSelect = (upWindow == mMacWindowP);
}
}
if (doSelect) { // Selecting a Window brings it to the
// front of its layer and activates it
UDesktop::SelectDeskWindow(this);
respondToClick = HasAttribute(windAttr_GetSelectClick);
}
}
if (respondToClick && !theMouseDown.delaySelect) {
theMouseDown.delaySelect = false;
Click(theMouseDown);
}
}
// ---------------------------------------------------------------------------
// • ClickInDrag
// ---------------------------------------------------------------------------
// Handle click in drag region of a Window
void
LWindow::ClickInDrag(
const EventRecord& inMacEvent)
{
// Save old bounds (content region
// is in global coords)
Rect bounds = (*((WindowPeek)mMacWindowP)->contRgn)->rgnBBox;
Rect dragRect = (**(GetGrayRgn())).rgnBBox;
InsetRect(&dragRect, 4, 4);
UDesktop::DragDeskWindow(this, inMacEvent, dragRect);
// DragWindow will move the window. However, send AppleEvent to
// set the bounds (but don't execute it), so that Script engines
// can record the action.
// Compare old and new bounds
if (!EqualRect(&bounds,
&(*((WindowPeek)mMacWindowP)->contRgn)->rgnBBox)) {
// Send but don't execute
// SetBounds AppleEvent
SendAESetPosition
(topLeft((*((WindowPeek)mMacWindowP)->contRgn)->rgnBBox),
false);
Point offset = {0, 0}; // Dragging window offsets the
PortToGlobalPoint(offset); // position of the UserBounds
offset.h -= mUserBounds.left; // for zooming
offset.v -= mUserBounds.top;
OffsetRect(&mUserBounds, offset.h, offset.v);
mMoveOnlyUserZoom = false;
}
}
// ---------------------------------------------------------------------------
// • ClickInGrow
// ---------------------------------------------------------------------------
void
LWindow::ClickInGrow(
const EventRecord& inMacEvent)
{
long newSize; // New width and height for window
Rect theRect; // Utility rectangle
theRect = mMinMaxSize; // Store instance variable in local
// var in case memory moves
theRect.right += 1; // GrowWindow trap is off by one
theRect.bottom += 1; // when growing window to its max
// size. Mostly likely caused by
// using the PinRect trap.
// Let Toolbox draw the grow image
// newSize has the new height in
// the hi word, width in lo word
newSize = GrowWindow(mMacWindowP, inMacEvent.where, &theRect);
if (newSize != 0) { // If window size changed ...
// Get current bounds (global coords)
theRect = (*((WindowPeek)mMacWindowP)->contRgn)->rgnBBox;
// Compute new bounds (global coords)
theRect.right = theRect.left + LoWord(newSize);
theRect.bottom = theRect.top + HiWord(newSize);
// Change the window size
SendAESetBounds(&theRect, true);
}
}
// ---------------------------------------------------------------------------
// • ClickInGoAway
// ---------------------------------------------------------------------------
// Handle a click inside the close box of a Window
void
LWindow::ClickInGoAway(
const EventRecord& inMacEvent)
{
if (TrackGoAway(mMacWindowP, inMacEvent.where)) {
SendAEClose();
}
}
// ---------------------------------------------------------------------------
// • ClickInZoom
// ---------------------------------------------------------------------------
// Handle a click inside the zoom box of a Window
void
LWindow::ClickInZoom(
const EventRecord& inMacEvent,
short inZoomDirection)
{
if (TrackBox(mMacWindowP, inMacEvent.where, inZoomDirection)) {
SendAESetZoom();
}
}
// ---------------------------------------------------------------------------
// • UpdatePort
// ---------------------------------------------------------------------------
// Redraw invalidated area of the Window
//
// The Mac WindowPtr maintains an update region that defines the area
// that needs to be redrawn.
void
LWindow::UpdatePort()
{
GrafPtr originalPort;
GetPort(&originalPort);
SetPort(mMacWindowP);
SetOrigin(0,0);
OutOfFocus(nil);
BeginUpdate(mMacWindowP);
Draw(mMacWindowP->visRgn);
EndUpdate(mMacWindowP);
SetPort(originalPort);
OutOfFocus(nil);
}
// ---------------------------------------------------------------------------
// • EstablishPort
// ---------------------------------------------------------------------------
// Make Window the current Port
void
LWindow::EstablishPort()
{
if ((mMacWindowP != nil) && (qd.thePort != mMacWindowP)) {
SetPort(mMacWindowP);
}
}
void
LWindow::InvalPortRect(
const Rect *inRect)
{
FocusDraw();
::InvalRect(inRect);
}
void
LWindow::InvalPortRgn(
RgnHandle inRgnH)
{
FocusDraw();
::InvalRgn(inRgnH);
}
void
LWindow::ValidPortRect(
const Rect *inRect)
{
FocusDraw();
::ValidRect(inRect);
}
void
LWindow::ValidPortRgn(
RgnHandle inRgnH)
{
FocusDraw();
::ValidRgn(inRgnH);
}
void
LWindow::Select()
{
UDesktop::SelectDeskWindow(this);
}
void
LWindow::Show()
{
if (mVisible == triState_Off) {
mVisible = triState_On;
ShowSelf();
LView::Show();
}
}
void
LWindow::ShowSelf()
{
UDesktop::ShowDeskWindow(this);
}
void
LWindow::HideSelf()
{
UDesktop::HideDeskWindow(this);
}
void
LWindow::Activate()
{
if (mActive == triState_Off) {
mActive = triState_On;
ActivateSelf();
LView::Activate();
// Normally the active Window contains the Target. If this
// Window can be the Target, restore the Target to what
// it was when the Window was last active. Don't do this
// if the Window is already on duty (which happens when
// the Window is a Superior of a Window that was just
// deactivated).
if (HasAttribute(windAttr_Targetable) && !IsOnDuty()) {
RestoreTarget();
}
}
}
void
LWindow::ActivateSelf()
{
HiliteWindow(mMacWindowP, true);
DrawSizeBox();
}
void
LWindow::Deactivate()
{
LView::Deactivate();
if (IsOnDuty()) {
// Switch target to SuperCommander to prevent an
// inactive Window from containing the Target
SwitchTarget(GetSuperCommander());
}
}
void
LWindow::DeactivateSelf()
{
HiliteWindow(mMacWindowP, false);
DrawSizeBox();
}
void
LWindow::Enable()
{
if (mEnabled == triState_Off) {
mEnabled = triState_On;
EnableSelf();
LView::Enable();
}
}
void
LWindow::Suspend()
{
if (HasAttribute(windAttr_HideOnSuspend)) {
SuperHide();
} else if (IsActive()) {
Deactivate();
}
}
void
LWindow::Resume()
{
if (HasAttribute(windAttr_HideOnSuspend)) {
HiliteWindow(mMacWindowP, true);
SuperShow();
}
}
void
LWindow::DrawSelf()
{
// PaintRect(&mMacWindowP->portRect); // DEBUG, for checking update region
if (HasAttribute(windAttr_EraseOnUpdate)) {
EraseRect(&mMacWindowP->portRect);
}
DrawSizeBox();
}
// ---------------------------------------------------------------------------
// • DrawSizeBox
// ---------------------------------------------------------------------------
// Draw standard size box for resizable Windows
void
LWindow::DrawSizeBox()
{
if (HasAttribute(windAttr_SizeBox)) {
// The Toolbox trap DrawGrowIcon draws the size box in
// the lower right corner of a Window, but it also outlines
// the typical scroll bar areas at the right and bottom of
// a Window. We want this routine to work for Windows that
// don't necessarily have standard scroll bars, so we
// temporarily change the clipping region to draw just the
// size box.
FocusDraw();
RgnHandle saveClip = NewRgn();
GetClip(saveClip);
Rect sizeBox = mMacWindowP->portRect;
sizeBox.left = sizeBox.right - 15;
sizeBox.top = sizeBox.bottom - 15;
ClipRect(&sizeBox);
DrawGrowIcon(mMacWindowP);
SetClip(saveClip);
DisposeRgn(saveClip);
}
}
static Boolean // ### put in a utility class
IsColorGrafPort(
GrafPtr inMacPortP)
{
// Highest 2 bits of rowBytes are
// set for a Color GrafPort
return ((inMacPortP->portBits.rowBytes & 0xC000) == 0xC000);
}
// ---------------------------------------------------------------------------
// • GlobalToPortPoint
// ---------------------------------------------------------------------------
// Convert a point from global (screen) coordinates to a Window's Port
// coordinates
void
LWindow::GlobalToPortPoint(
Point &ioPoint) const
{
// Windows have a reference to the pixel image of the main screen--
// portBits for B&W and portPixMap for color windows. The bounds
// of the pixel image specify the alignment of the *local* Window
// coordinates with *global* coordinates:
// localPt = globalPt + topLeft(imageBounds)
//
// To convert from *local* to *port* coordinates, we offset by
// the top left of the Window's port rectangle:
// portPt = localPt - topLeft(portRect)
//
// Therefore,
// portPt = globalPt + topLeft(imageBounds) - topLeft(portRect)
//
// Note: We don't use the Toolbox routine GlobalToLocal because
// that routine depends on the current port and the current port
// origin. To use GlobalToLocal we would have to do the following:
// GrafPtr savePort;
// GetPort(&savePort);
// Point saveOrigin = topLeft(mMacWindowP->portRect);
// SetPort(mMacWindowP);
// SetOrigin(0,0);
// GlobalToLocal(ioPoint);
// SetOrigin(saveOrigin.h, saveOrigin.v);
// SetPort(savePort);
// The equation above avoids all this saving/setting/restoring
// of the current port and port origin.
// Assume a B&W Window
Point localOffset = topLeft(mMacWindowP->portBits.bounds);
if (IsColorGrafPort(mMacWindowP)) {
// Nope, it's a color Window
CGrafPtr colorPortP = (CGrafPtr) mMacWindowP;
localOffset = topLeft((**(colorPortP->portPixMap)).bounds);
}
ioPoint.h += (localOffset.h - mMacWindowP->portRect.left);
ioPoint.v += (localOffset.v - mMacWindowP->portRect.top);
}
// ---------------------------------------------------------------------------
// • PortToGlobalPoint
// ---------------------------------------------------------------------------
// Convert a point from Port to Global (screen) coordinates
// [see discussion above for GlobalToPortPoint() for comments]
void
LWindow::PortToGlobalPoint(
Point &ioPoint) const
{
// Assume a B&W Window
Point localOffset = topLeft(mMacWindowP->portBits.bounds);
if (IsColorGrafPort(mMacWindowP)) {
// Nope, it's a color Window
CGrafPtr colorPortP = (CGrafPtr) mMacWindowP;
localOffset = topLeft((**(colorPortP->portPixMap)).bounds);
}
ioPoint.h -= (localOffset.h - mMacWindowP->portRect.left);
ioPoint.v -= (localOffset.v - mMacWindowP->portRect.top);
}
// ===========================================================================
// • Sending Apple Events Sending Apple Events •
// ===========================================================================
// ---------------------------------------------------------------------------
// • SendAESetPosition
// ---------------------------------------------------------------------------
// AppleEvent for moving a Window to a new position
//
// inPosition is the location for the top left corner of the Window's
// port rectangle, in Global coordinates
// Set inExecuteAE to true to actually move the Window, false to
// just send the event for script recording purposes. You'll use the
// false value when you have already moved the window in response to
// tracking user actions (the Toolbox trap DragWindow move the Window).
void
LWindow::SendAESetPosition(
Point inPosition,
Boolean inExecuteAE)
{
Try_
LModelProperty* positionProperty = new LModelProperty(pPosition, this);
positionProperty->SendSetDataAE(typeQDPoint, (Ptr) &inPosition,
sizeof(Point), inExecuteAE);
delete positionProperty;
}
// ---------------------------------------------------------------------------
// • SendAESetBounds
// ---------------------------------------------------------------------------
// AppleEvent for changing the size of a Window
//
// inBounds is the new port rectangle for the Window, in Global coordinates.
// Set inExecuteAE to true to actually resize the Window, false to
// just send the event for script recording purposes.
void
LWindow::SendAESetBounds(
Rect *inBounds, // New bounds in global coords
Boolean inExecuteAE)
{
Try_
LModelProperty* positionProperty = new LModelProperty(pBounds, this);
positionProperty->SendSetDataAE(typeQDRectangle, (Ptr) inBounds,
sizeof(Rect), inExecuteAE);
delete positionProperty;
}
// ---------------------------------------------------------------------------
// • SendAESetZoom
// ---------------------------------------------------------------------------
// AppleEvent for zooming a Window
//
// This function figures out whether to zoom in or out based on the
// current window size and location
void
LWindow::SendAESetZoom()
{
// Determine zoom direction
Rect stdBounds;
Boolean zoomToStdState = !CalcStandardBounds(stdBounds);
Try_
LModelProperty* zoomProperty = new LModelProperty(pIsZoomed, this);
zoomProperty->SendSetDataAE(typeBoolean, (Ptr) &zoomToStdState,
sizeof(Boolean), true);
delete zoomProperty;
}
// ---------------------------------------------------------------------------
// • SendAEClose
// ---------------------------------------------------------------------------
// AppleEvent for closing a Window
void
LWindow::SendAEClose()
{
Try_
AppleEvent theAppleEvent;
UAppleEvents::MakeAppleEvent(kAECoreSuite, kAEClose, theAppleEvent);
CheckThrow_
StAEDescriptor windowSpec;
MakeSpecifier(windowSpec.mDesc);
CheckThrow_
OSErr err = AEPutParamDesc(&theAppleEvent, keyDirectObject,
&windowSpec.mDesc);
if (err != noErr) Throw_(err);
UAppleEvents::SendAppleEvent(theAppleEvent, true);
}
// ===========================================================================
// • Responding To Apple Events Responding To Apple Events •
// ===========================================================================
OSErr
LWindow::DoAEClose()
{
if ( (GetSuperCommander() == nil) ||
GetSuperCommander()->AllowSubRemoval(this) ) {
// Set flag to delete Window after completion
// of the Close AppleEvent
DeleteWhenFinished(true);
}
return noErr;
}
// ---------------------------------------------------------------------------
// • ObeyCommand
// ---------------------------------------------------------------------------
// Handle a command
Boolean
LWindow::ObeyCommand(
CommandT inCommand,
void *ioParam)
{
Boolean cmdHandled = true;
switch (inCommand) {
case cmd_Close:
SendAEClose();
break;
default:
cmdHandled = LCommander::ObeyCommand(inCommand, ioParam);
break;
}
return cmdHandled;
}
// ---------------------------------------------------------------------------
// • FindCommandStatus
// ---------------------------------------------------------------------------
// Return whether a Command is enabled and/or marked (in a Menu)
void
LWindow::FindCommandStatus(
CommandT inCommand,
Boolean &outEnabled,
Boolean &outUsesMark,
Char16 &outMark)
{
switch (inCommand) {
case cmd_Close:
outEnabled = true;
outUsesMark = false;
break;
default:
LCommander::FindCommandStatus(inCommand, outEnabled,
outUsesMark, outMark);
break;
}
}
// ===========================================================================
// • AppleEvent Object Model Support AppleEvent Object Model Support •
// ===========================================================================
DescType
LWindow::GetModelKind() const
{
return cWindow;
}
void
LWindow::MakeSelfSpecifier(
AEDesc &inSuperSpecifier,
AEDesc &outSelfSpecifier) const
{
AEDesc keyData;
Int16 windowIndex = FindWindowIndex(mMacWindowP);
OSErr err = CreateOffsetDescriptor(windowIndex, &keyData);
if (err != noErr) Throw_(err);
err = CreateObjSpecifier(cWindow, &inSuperSpecifier, formAbsolutePosition,
&keyData, true, &outSelfSpecifier);
if (err != noErr) Throw_(err);
}
LModelProperty*
LWindow::GetModelProperty(
DescType inProperty)
{
LModelProperty *theProperty = nil;
switch (inProperty) {
case pName:
case pPosition:
case pBounds:
case pIsZoomed:
case pHasCloseBox:
case pHasTitleBar:
case pIsFloating:
case pIsModal:
case pIsResizable:
case pIsZoomable:
case pVisible:
theProperty = new LModelProperty(inProperty, this);
break;
default:
theProperty = LModelObject::GetModelProperty(inProperty);
}
return theProperty;
}
void
LWindow::GetAEProperty(
DescType inProperty,
const AEDesc &inRequestedType,
AEDesc &outPropertyDesc) const
{
OSErr err;
switch (inProperty) {
case pName: // Window Title
Str255 theName;
GetDescriptor(theName);
err = AECreateDesc(typeChar, (Ptr) theName + 1,
Length(theName), &outPropertyDesc);
break;
case pPosition: // Top left of Frame in Global coords
Point thePosition = {0, 0};
PortToGlobalPoint(thePosition);
err = AECreateDesc(typeQDPoint, (Ptr) &thePosition,
sizeof(Point), &outPropertyDesc);
break;
case pBounds: // Frame in Global coords
Rect theBounds;
CalcPortFrameRect(theBounds);
PortToGlobalPoint(topLeft(theBounds));
PortToGlobalPoint(botRight(theBounds));
err = AECreateDesc(typeQDRectangle, (Ptr) &theBounds,
sizeof(Rect), &outPropertyDesc);
break;
case pIsZoomed: // Is Window at Standard state?
Rect stdBounds;
Boolean isZoomed = CalcStandardBounds(stdBounds);
err = AECreateDesc(typeBoolean, (Ptr) &isZoomed,
sizeof(Boolean), &outPropertyDesc);
break;
case pHasCloseBox:
GetAEWindowAttribute(windAttr_CloseBox, outPropertyDesc);
break;
case pHasTitleBar:
GetAEWindowAttribute(windAttr_TitleBar, outPropertyDesc);
break;
case pIsFloating:
GetAEWindowAttribute(windAttr_Floating, outPropertyDesc);
break;
case pIsModal:
GetAEWindowAttribute(windAttr_Modal, outPropertyDesc);
break;
case pIsResizable:
GetAEWindowAttribute(windAttr_Resizable, outPropertyDesc);
break;
case pIsZoomable: // Can Window be zoomed?
GetAEWindowAttribute(windAttr_Zoomable, outPropertyDesc);
break;
case pVisible:
Boolean isVis = IsVisible();
err = AECreateDesc(typeBoolean, (Ptr) &isVis,
sizeof(Boolean), &outPropertyDesc);
break;
default:
LModelObject::GetAEProperty(inProperty, inRequestedType,
outPropertyDesc);
break;
}
}
void
LWindow::SetAEProperty(
DescType inProperty,
const AEDesc &inValue,
AEDesc& outAEReply)
{
switch (inProperty) {
case pName:
Str255 theName;
UExtractFromAEDesc::ThePString(inValue, theName);
CheckThrow_
SetDescriptor(theName);
break;
case pPosition:
Point thePosition;
UExtractFromAEDesc::ThePoint(inValue, thePosition);
CheckThrow_
DoSetPosition(thePosition);
break;
case pBounds:
Rect theBounds;
UExtractFromAEDesc::TheRect(inValue, theBounds);
CheckThrow_
DoSetBounds(theBounds);
break;
case pIsZoomed:
Boolean isZoomed;
UExtractFromAEDesc::TheBoolean(inValue, isZoomed);
CheckThrow_
DoSetZoom(isZoomed);
break;
case pVisible:
Boolean makeVisible;
UExtractFromAEDesc::TheBoolean(inValue, makeVisible);
CheckThrow_
if (makeVisible) {
Show();
} else {
Hide();
}
break;
default:
LModelObject::SetAEProperty(inProperty, inValue, outAEReply);
break;
}
}
void
LWindow::GetAEWindowAttribute(
Uint16 inAttribute,
AEDesc &outPropertyDesc) const
{
Boolean attrIsSet = HasAttribute(inAttribute);
OSErr err = AECreateDesc(typeBoolean, (Ptr) &attrIsSet,
sizeof(Boolean), &outPropertyDesc);
}
void
LWindow::HandleAppleEvent(
const AppleEvent& inAppleEvent,
AppleEvent& outAEReply,
long inAENumber)
{
switch (inAENumber) {
case ae_Close:
DoAEClose();
break;
default:
LModelObject::HandleAppleEvent(inAppleEvent, outAEReply,
inAENumber);
break;
}
}
// ---------------------------------------------------------------------------
// • DoSetPosition
// ---------------------------------------------------------------------------
// Change the location of a Window
//
// The top left corner of the Window's port rectangle is placed at
// inPosition, which is in global coordinates
void
LWindow::DoSetPosition(
Point inPosition) // Top left in global coords
{
MoveWindow(mMacWindowP, inPosition.h, inPosition.v, false);
Point offset = {0, 0}; // Moving Window changes the
PortToGlobalPoint(offset); // UserBounds for zooming
offset.h -= mUserBounds.left;
offset.v -= mUserBounds.top;
OffsetRect(&mUserBounds, offset.h, offset.v);
mMoveOnlyUserZoom = false;
}
// ---------------------------------------------------------------------------
// • CalcStandardBounds
// ---------------------------------------------------------------------------
// Calculate the bounds of the Window at standard state and return whether
// it is at standard state. The standard state depends on the screen
// containing the largest area of the Window and the current standard size.
//
// outStdBounds: Port rectangle of Window at standard size, global coords
Boolean
LWindow::CalcStandardBounds(
Rect &outStdBounds) const
{
// Find GDevice containing largest
// portion of Window
GDHandle dominantDevice = UWindows::FindDominantDevice(
UWindows::GetWindowStructureRect(mMacWindowP));
// Must compensate for MenuBar on the
// main screen
Rect screenRect = (**dominantDevice).gdRect;
if (dominantDevice == ::GetMainDevice()) {
screenRect.top += GetMBarHeight();
}
CalcStandardBoundsForScreen(screenRect, outStdBounds);
return ::EqualRect(&outStdBounds,
&UWindows::GetWindowContentRect(mMacWindowP));
}
// ---------------------------------------------------------------------------
// • CalcStandardBoundsForScreen
// ---------------------------------------------------------------------------
// Calculate the bounds of the Window if it was at a Standard (zoomed out)
// state on a Screen with the specified bounds.
//
// inScreenBounds: Bounding box of screen in global coordinates
// outStdBounds: Port rectangle of Window at standard size, global coords
void
LWindow::CalcStandardBoundsForScreen(
const Rect &inScreenBounds,
Rect &outStdBounds) const
{
// Structure and Content regions are
// in global coordinates
Rect strucRect = UWindows::GetWindowStructureRect(mMacWindowP);
Rect contRect = UWindows::GetWindowContentRect(mMacWindowP);
// Structure can be (and usually is)
// larger than Content
Rect border;
border.left = contRect.left - strucRect.left;
border.right = strucRect.right - contRect.right;
border.top = contRect.top - strucRect.top;
border.bottom = strucRect.bottom - contRect.bottom;
// Don't zoom too close to edge of screen
Int16 screenWidth = inScreenBounds.right - inScreenBounds.left - 4;
Int16 screenHeight = inScreenBounds.bottom - inScreenBounds.top - 4;
// Standard dimensions are the minimum
// of mStandardSize and the size of
// the screen
Int16 stdWidth = mStandardSize.width;
if (stdWidth > screenWidth - (border.left + border.right)) {
stdWidth = screenWidth - (border.left + border.right);
}
Int16 stdHeight = mStandardSize.height;
if (stdHeight > screenHeight - (border.top + border.bottom)) {
stdHeight = screenHeight - (border.top + border.bottom);
}
// Standard position is the point closest
// to the current position at which
// the Window will be all on screen
// Move window horizontally so that left
// or right edge of Struction region is
// 2 pixels from the edge of the screen
Int16 stdLeft = contRect.left;
if (stdLeft < inScreenBounds.left + border.left + 2) {
stdLeft = inScreenBounds.left + border.left + 2;
} else if (stdLeft > inScreenBounds.right - stdWidth - border.right - 2) {
stdLeft = inScreenBounds.right - stdWidth - border.right - 2;
}
// Move window vertically so that top
// or bottom edge of Struction region is
// 2 pixels from the edge of the screen
Int16 stdTop = contRect.top;
if (stdTop < inScreenBounds.top + border.top + 2) {
stdTop = inScreenBounds.top + border.top + 2;
} else if (stdTop > inScreenBounds.bottom - stdHeight - border.bottom - 2) {
stdTop = inScreenBounds.bottom - stdHeight - border.bottom - 2;
}
outStdBounds.left = stdLeft;
outStdBounds.right = stdLeft + stdWidth;
outStdBounds.top = stdTop;
outStdBounds.bottom = stdTop + stdHeight;
}
// ---------------------------------------------------------------------------
// • DoSetZoom
// ---------------------------------------------------------------------------
// Zoom window to either the Standard or User state
void
LWindow::DoSetZoom(
Boolean inZoomToStdState)
{
if (!HasAttribute(windAttr_Zoomable)) {
Throw_(errAENotModifiable);
}
Rect currBounds = UWindows::GetWindowContentRect(mMacWindowP);
Rect zoomBounds;
if (inZoomToStdState) { // Zoom to Standard state
if (CalcStandardBounds(zoomBounds)) {
return; // Already at Standard state
}
} else { // Zoom to User state
zoomBounds = mUserBounds;
if (mMoveOnlyUserZoom) { // Special case for zooming a Window
// that is at standard size, but
// is partially offscreen
zoomBounds.right = zoomBounds.left +
(currBounds.right - currBounds.left);
zoomBounds.bottom = zoomBounds.top +
(currBounds.bottom - currBounds.top);
}
}
Int16 zoomWidth = zoomBounds.right - zoomBounds.left;
Int16 zoomHeight = zoomBounds.bottom - zoomBounds.top;
mMoveOnlyUserZoom = false;
// To avoid unnecessary redraws, we check to see if the
// current and zoom states are either the same size
// or at the same location
if ( ((currBounds.right - currBounds.left) == zoomWidth) &&
((currBounds.bottom - currBounds.top) == zoomHeight) ) {
// Same size, just move
MoveWindow(mMacWindowP, zoomBounds.left, zoomBounds.top, false);
mMoveOnlyUserZoom = true;
} else if (EqualPt(topLeft(currBounds), topLeft(zoomBounds))) {
// Same location, just resize
SizeWindow(mMacWindowP, zoomWidth, zoomHeight, false);
ResizeFrameTo(zoomWidth, zoomHeight, true);
} else { // Different size and location
// Stuff zoom bounds into WindowRecord
// as standard state and zoom out
WStateDataHandle wStateH = (WStateDataHandle)
((WindowPeek) mMacWindowP)->dataHandle;
(**wStateH).stdState = zoomBounds;
FocusDraw();
EraseRect(&mMacWindowP->portRect);
ZoomWindow(mMacWindowP, inZoomOut, false);
ResizeFrameTo(zoomWidth, zoomHeight, false);
}
}
// ---------------------------------------------------------------------------
// • DoSetBounds
// ---------------------------------------------------------------------------
// Change size and location of a Window
//
// inBounds, in global coords, specifies the new size and location of
// the Window's port rectangle
void
LWindow::DoSetBounds(
const Rect &inBounds) // Bounds in global coords
{
SizeWindow(mMacWindowP, inBounds.right - inBounds.left,
inBounds.bottom - inBounds.top, false);
MoveWindow(mMacWindowP, inBounds.left, inBounds.top, false);
ResizeFrameTo(inBounds.right - inBounds.left,
inBounds.bottom - inBounds.top, true);
SDimension16 frameSize; // For Windows, Image is always the
GetFrameSize(frameSize); // same size as its Frame
ResizeImageTo(frameSize.width, frameSize.height, false);
// Changing Bounds establishes a
// new User state for zooming
CalcPortFrameRect(mUserBounds);
PortToGlobalPoint(topLeft(mUserBounds));
PortToGlobalPoint(botRight(mUserBounds));
mMoveOnlyUserZoom = false;
}
// ===========================================================================
// • Static Member Functions Static Member Functions •
// ===========================================================================
// ---------------------------------------------------------------------------
// • FindNthWindow
// ---------------------------------------------------------------------------
// Return a WindowPtr to the Nth Window
//
// Windows are ordered from front to back
// For positive indexes, 1 is the front window, 2 is the second, etc.
// For negative indexes, -1 is the last window, -2 next to last, etc.
// If Abs(N) > number of windows or N = 0, return nil
WindowPtr
LWindow::FindNthWindow(
Int16 inN)
{
WindowPeek theWindowP = nil;
Int16 wIndex = inN;
if (wIndex < 0) { // Negative index counts from end
Int16 windowCount = 0; // Count how many windows there are
theWindowP = LMGetWindowList();
while (theWindowP) {
windowCount++;
theWindowP = theWindowP->nextWindow;
} // Compute positive index
wIndex = windowCount + wIndex + 1;
}
if (wIndex > 0) { // Count down into linked list
theWindowP = LMGetWindowList();
while (--wIndex && theWindowP) {
theWindowP = theWindowP->nextWindow;
}
}
return (WindowPtr) theWindowP;
}
// ---------------------------------------------------------------------------
// • FindWindowIndex
// ---------------------------------------------------------------------------
// Return index position of Window with the Application
//
// Windows are ordered from front to back, with #1 being the front window.
// If inWindowP is not found, returns 0;
Int16
LWindow::FindWindowIndex(
WindowPtr inWindowP)
{
Int16 index = 1;
WindowPeek currWindowP = LMGetWindowList();
while (currWindowP && (currWindowP != (WindowPeek) inWindowP)) {
index++;
currWindowP = currWindowP->nextWindow;
}
if (currWindowP == nil) {
index = 0;
}
return index;
}